import  fs from 'fs';
import parser from '@babel/parser';
import path from 'path';
import traverse from '@babel/traverse';
import ejs from 'ejs';
import { transformFromAst } from 'babel-core';
import {jsonLoader} from './jsonLoader.js'
import { SyncHook } from 'tapable';

import {ChangeOutputPath} from './ChangeOutputPath.js'
let id = 0

const webpackConfig = {
    module: {
        rules: [
            {
                test: /\.json$/,
                use: [jsonLoader],
            }, 
        ],
    },

    plugins: [new ChangeOutputPath()],

};

// plugin事件注册
const hooks = {
    emitFile : new SyncHook(["context"])
}

function createAsset(filePath){
    // 1. 获取文件内容
    // 2. 获取依赖关系
    // 3. ast -> 获取代码信息
    let source = fs.readFileSync(filePath, {
        encoding: "utf-8"
    })

    // initLoader
    const loaders = webpackConfig.module.rules
    const loaderContext = {
        add(dep){
            console.log("addDeps", dep)
        }
    }

    loaders.forEach(({test,use}) => {
        if(test.test(filePath)){
            if(Array.isArray(use)){
                use.forEach((fn) => {
                    source = fn.call(loaderContext,source)
                })
            }else{
                source = use(source)
            }
        }
    })
    const ast = parser.parse(source, {
        sourceType: "module"
    })
    // console.log(ast)

    // 依赖关系收集
    const deps = []

    traverse.default(ast, {
        ImportDeclaration( {node} ){
            deps.push(node.source.value)
        }
    })

    const {code} = transformFromAst(ast, null,{
        presets: ["env"],

    })
    // console.log(code);

    return {
        filePath,
        code,
        deps,
        id: id++,
        mapping: {}
    }
}

// const asset = createAsset()

// console.log(asset);

function createCraph(){
    const mainAsset = createAsset("./example/main.js");

    const queue = [mainAsset]

    for(const asset of queue){
        asset.deps.forEach((relativePath) => {
            const child = createAsset(path.resolve("./example", relativePath))
            asset.mapping[relativePath] = child.id
            queue.push(child)
        })
    }
    // console.log(queue);
    return queue
}

function initPlugins(hooks) {
    const plugins = webpackConfig.plugins;
    plugins.forEach(plugin => {
        plugin.apply(hooks);
    })
}

initPlugins(hooks)



const graph =  createCraph();

// console.log(graph);

function build(graph){
    const template = fs.readFileSync("./bundle.ejs",{encoding: "utf-8"})
   
    const data = graph.map((asset) => {
        return {
            id: asset.id,
            code:asset.code,
            mapping: asset.mapping
        }
    })

    const code = ejs.render(template, {data})

    let outputPath = "./dist/bundle.js"

    const context = {
        changeOutputPath(path){
            outputPath = path
        }
    }

    // plugin事件触发
    hooks.emitFile.call(context)
    fs.writeFileSync(outputPath, code)
    // console.log(data)
}
build(graph)